{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Don't Use *args and **kwargs Names Blindly"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In most of the code we have been working with we used `*args` and `**kwargs`. But these were small code snippets where the argument names did not necessarily have meaning, or were used very generically such as with decorators.\n",
    "\n",
    "In your code, if those variable positional and keyword-only arguments have meaning, then use a meaningful name instead of just `*args` and `**kwargs`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Example 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here, using the conventional names `args` and `kwargs` makes sense since we have no idea what those are - we are simply using them as a pass through to call another function in our decorator:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def audit(f):\n",
    "    def inner(*args, **kwargs):\n",
    "        print(f'Called {f.__name__}')\n",
    "        return f(*args, **kwargs)\n",
    "    return inner"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "But for the following `product` function, it makes more sense to use `*values` than `*args`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "@audit\n",
    "def say_hello(name):\n",
    "    return f'Hello {name}'\n",
    "\n",
    "from operator import mul\n",
    "from functools import reduce\n",
    "\n",
    "@audit\n",
    "def product(*values):\n",
    "    return reduce(mul, values)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Called say_hello\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'Hello Polly'"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "say_hello('Polly')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Called product\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "24"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "product(1, 2, 3, 4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Example 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Same thing here - using `*item_values` makes more sense than `*args`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def count_multi(lst, *item_values):\n",
    "    return sum(lst.count(value) for value in item_values)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "l = 1, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "count_multi(l, 1, 6, 7)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Example 3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Suppose we want our class init to allow people to send in additional arbitrary (custom) instance attributes:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Person:\n",
    "    def __init__(self, name, age, **custom_attributes):\n",
    "        self.name = name\n",
    "        self.age = age\n",
    "        for attr_name, attr_value in custom_attributes.items():\n",
    "            setattr(self, attr_name, attr_value)        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "parrot = Person('Polly', 101, status='stiff', vooms=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'name': 'Polly', 'age': 101, 'status': 'stiff', 'vooms': False}\n"
     ]
    }
   ],
   "source": [
    "print(vars(parrot))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "michael = Person('Michael', 42, role='shopkeeper', crooked=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'name': 'Michael', 'age': 42, 'role': 'shopkeeper', 'crooked': True}\n"
     ]
    }
   ],
   "source": [
    "print(vars(michael))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
